home *** CD-ROM | disk | FTP | other *** search
- /* advexe.c - adventure code executer */
- /*
- Copyright (c) 1986, by David Michael Betz
- All rights reserved
- */
-
- #include "advint.h"
- #include "advdbs.h"
-
- /* external variables */
- extern char line[];
- extern int nouns[],*adjectives[];
-
- /* local variables */
- int pc,opcode,p2,p3,sts;
- int stack[STKSIZE],*sp,*fp,*top;
- long rseed = 1L;
-
- /* external routines */
- extern long time();
-
- /* execute - execute adventure code */
- int execute(code)
- int code;
- {
- /* setup initial program counter */
- if ((pc = code) == NIL)
- return (CHAIN);
-
- /* initialize */
- sp = fp = top = stack + STKSIZE;
-
- /* execute the code */
- for (sts = 0; sts == 0; )
- exe_one();
-
- return (sts);
- }
-
- /* exe_one - execute one instruction */
- exe_one()
- {
- /* get the opcode */
- opcode = getcbyte(pc); pc++;
-
- /* execute the instruction */
- switch (opcode) {
- case OP_CALL:
- *--sp = getboperand();
- *--sp = pc;
- *--sp = (int)(top - fp);
- fp = sp;
- pc = getafield(fp[fp[2]+3],A_CODE);
- break;
- case OP_SEND:
- *--sp = getboperand();
- *--sp = pc;
- *--sp = (int)(top - fp);
- fp = sp;
- if (p2 = fp[fp[2]+3])
- p2 = getofield(p2,O_CLASS);
- else
- p2 = fp[fp[2]+2];
- if (p2 && (p2 = getp(p2,fp[fp[2]+1]))) {
- pc = getafield(p2,A_CODE);
- break;
- }
- *sp = NIL;
- /* return NIL if there is no method for this message */
- case OP_RETURN:
- if (fp == top)
- sts = CHAIN;
- else {
- p2 = *sp;
- sp = fp;
- fp = top - *sp++;
- pc = *sp++;
- p3 = *sp++;
- sp += p3;
- *sp = p2;
- }
- break;
- case OP_TSPACE:
- sp -= getboperand();
- break;
- case OP_TMP:
- p2 = getboperand();
- *sp = fp[-p2-1];
- break;
- case OP_TSET:
- p2 = getboperand();
- fp[-p2-1] = *sp;
- break;
- case OP_ARG:
- p2 = getboperand();
- if (p2 >= fp[2])
- error("too few arguments");
- *sp = fp[p2+3];
- break;
- case OP_ASET:
- p2 = getboperand();
- if (p2 >= fp[2])
- error("too few arguments");
- fp[p2+3] = *sp;
- break;
- case OP_BRT:
- pc = (*sp ? getwoperand() : pc+2);
- break;
- case OP_BRF:
- pc = (*sp ? pc+2 : getwoperand());
- break;
- case OP_BR:
- pc = getwoperand();
- break;
- case OP_T:
- *sp = T;
- break;
- case OP_NIL:
- *sp = NIL;
- break;
- case OP_PUSH:
- *--sp = NIL;
- break;
- case OP_NOT:
- *sp = (*sp ? NIL : T);
- break;
- case OP_ADD:
- p2 = *sp++;
- *sp += p2;
- break;
- case OP_SUB:
- p2 = *sp++;
- *sp -= p2;
- break;
- case OP_MUL:
- p2 = *sp++;
- *sp *= p2;
- break;
- case OP_DIV:
- p2 = *sp++;
- *sp = (p2 == 0 ? 0 : *sp / p2);
- break;
- case OP_REM:
- p2 = *sp++;
- *sp = (p2 == 0 ? 0 : *sp % p2);
- break;
- case OP_BAND:
- p2 = *sp++;
- *sp &= p2;
- break;
- case OP_BOR:
- p2 = *sp++;
- *sp |= p2;
- break;
- case OP_BNOT:
- *sp = ~*sp;
- break;
- case OP_LT:
- p2 = *sp++;
- *sp = (*sp < p2 ? T : NIL);
- break;
- case OP_EQ:
- p2 = *sp++;
- *sp = (*sp == p2 ? T : NIL);
- break;
- case OP_GT:
- p2 = *sp++;
- *sp = (*sp > p2 ? T : NIL);
- break;
- case OP_LIT:
- *sp = getwoperand();
- break;
- case OP_SPLIT:
- *sp = getboperand();
- break;
- case OP_SNLIT:
- *sp = -getboperand();
- break;
- case OP_VAR:
- *sp = getvalue(getwoperand());
- break;
- case OP_SVAR:
- *sp = getvalue(getboperand());
- break;
- case OP_SET:
- setvalue(getwoperand(),*sp);
- break;
- case OP_SSET:
- setvalue(getboperand(),*sp);
- break;
- case OP_GETP:
- p2 = *sp++;
- *sp = getp(*sp,p2);
- break;
- case OP_SETP:
- p3 = *sp++;
- p2 = *sp++;
- *sp = setp(*sp,p2,p3);
- break;
- case OP_PRINT:
- print(*sp);
- break;
- case OP_PNUMBER:
- pnumber(*sp);
- break;
- case OP_PNOUN:
- show_noun(*sp);
- break;
- case OP_TERPRI:
- trm_chr('\n');
- break;
- case OP_FINISH:
- sts = FINISH;
- break;
- case OP_CHAIN:
- sts = CHAIN;
- break;
- case OP_ABORT:
- sts = ABORT;
- break;
- case OP_EXIT:
- #ifdef MAC
- macpause();
- #endif
- trm_done();
- exit();
- break;
- case OP_YORN:
- trm_get(line);
- *sp = (line[0] == 'Y' || line[0] == 'y' ? T : NIL);
- break;
- case OP_CLASS:
- *sp = getofield(*sp,O_CLASS);
- break;
- case OP_MATCH:
- p2 = *sp++;
- *sp = (match(*sp,nouns[p2-1],adjectives[p2-1]) ? T : NIL);
- break;
- case OP_SAVE:
- *sp = db_save();
- break;
- case OP_RESTORE:
- *sp = db_restore();
- break;
- case OP_RESTART:
- *sp = db_restart();
- break;
- case OP_RAND:
- *sp = getrand(*sp);
- break;
- case OP_RNDMIZE:
- setrand(time(0L));
- *sp = NIL;
- break;
- default:
- if (opcode >= OP_XVAR && opcode < OP_XSET)
- *sp = getvalue(opcode - OP_XVAR);
- else if (opcode >= OP_XSET && opcode < OP_XPLIT)
- setvalue(opcode - OP_XSET,*sp);
- else if (opcode >= OP_XPLIT && opcode < OP_XNLIT)
- *sp = opcode - OP_XPLIT;
- else if (opcode >= OP_XNLIT && opcode < 256)
- *sp = OP_XNLIT - opcode;
- else
- trm_str("Bad opcode\n");
- break;
- }
- }
-
- /* getboperand - get data byte */
- int getboperand()
- {
- int data;
- data = getcbyte(pc); pc += 1;
- return (data);
- }
-
- /* getwoperand - get data word */
- int getwoperand()
- {
- int data;
- data = getcword(pc); pc += 2;
- return (data);
- }
-
- /* print - print a message */
- print(msg)
- int msg;
- {
- int ch;
-
- msg_open(msg);
- while (ch = msg_byte())
- trm_chr(ch);
- }
-
- /* pnumber - print a number */
- pnumber(n)
- int n;
- {
- char buf[10];
-
- sprintf(buf,"%d",n);
- trm_str(buf);
- }
-
- /* getrand - get a random number between 0 and n-1 */
- int getrand(n)
- int n;
- {
- long k1;
-
- /* make sure we don't get stuck at zero */
- if (rseed == 0L) rseed = 1L;
-
- /* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */
- k1 = rseed / 127773L;
- if ((rseed = 16807L * (rseed - k1 * 127773L) - k1 * 2836L) < 0L)
- rseed += 2147483647L;
-
- /* return a random number between 0 and n-1 */
- return ((int)(rseed % (long)n));
- }
-
- /* setrand - set the random number seed */
- setrand(n)
- long n;
- {
- rseed = n;
- }
-